/**
 * 数学计算工具类
 */
export default class MathUtils {

    /**每天小时数 */
    public static readonly HOURS_PER_DAY = 24;
    /**每天分钟数 */
    public static readonly MINUTES_PER_DAY = 24 * 60;
    /**每天秒数 */
    public static readonly SECONDS_PER_DAY = 24 * 60 * 60;
    /**每天毫秒数 */
    public static readonly MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;

    /**
     * 随机范围整数
     * @param {number} min 最小值
     * @param {number} max 最大值
     * @returns {number} 返回随机整数包含 max
     */
    public static randomRangeInteger = (min: number, max: number): number => Math.floor(Math.random() * (max + 1 - min) + min);
    /**
    * 获取一个区间的随机数
    * @param $from 最小值
    * @param $end 最大值
    * @returns {number}
    */
    public static limit($from: number, $end: number): number {
        $from = Math.min($from, $end);
        $end = Math.max($from, $end);
        var range: number = $end - $from;
        return Math.random() * range + $from;
    }
    /**
     * 获取一个区间的随机数(整数)
     * @param $from 最小值 
     * @param $end 最大值
     * @returns {number}
     */
    public static limitInteger($from: number, $end: number): number {
        return Math.round(MathUtils.limit($from, $end));
    }
    /**
     * 在一个数组中随机获取一个元素
     * @param arr 数组
     * @returns {any} 随机出来的结果
     */
    public static randomArray<T>(arr: Array<T>): T {
        var index: number = Math.floor(Math.random() * arr.length);
        return arr[index];
    }

    /**
     * 随机打乱数组 es6 写法
     * @param arr 
     */
    public static shuffle<T>(arr: Array<T>) {
        let i = arr.length;
        while (--i) {
            let j = Math.floor(Math.random() * i);
            [arr[i], arr[j],] = [arr[j], arr[i]];
        }
    }
    // /**
    //  * 随机打乱数组 es5 写法
    //  * @param arr 
    //  */
    // public static shuffle(arr) {
    //     var i = arr.length, t, j;
    //     while (--i) {
    //         j = Math.floor(Math.random() * i);
    //         t = arr[i];
    //         arr[i] = arr[j];
    //         arr[j] = t;
    //     }
    // }

    /**
     * 角度转弧度
     */
    static deg2Rad: number = Math.PI / 180;

    /**
     * 弧度转角度
     */
    static rad2Deg: number = 180 / Math.PI;

    /**
     * 弧度值转换为角度值
     * @param radian 弧度值
     * @returns {number} 返回角度
     */
    public static radian2Angle(radian: number): number {
        return radian * 180 / Math.PI;
    }
    /**
       * 角度值转换为弧度值
       * @param {number} angle 角度
       * @returns {number} 返回弧度值
       */
    public static angle2Radian(angle: number): number {
        return angle * Math.PI / 180;
    }

    public static point2Angle(start, end) {
        var dx = start.x - end.x;
        var dy = start.y - end.y;
        var dir = cc.v2(dx, dy);
        var angle = dir.signAngle(cc.v2(1, 0));
        var degree = angle / Math.PI * 180;
        return -degree;
    }

    /**
     * 获取两点间弧度
     * @param p1X
     * @param p1Y
     * @param p2X
     * @param p2Y
     * @returns {number}
     */
    public static getRadian2(p1X: number, p1Y: number, p2X: number, p2Y: number): number {
        var xdis: number = p2X - p1X;
        var ydis: number = p2Y - p1Y;
        return Math.atan2(ydis, xdis);
    }
    /**
     * 两个向量获取弧度
     * @param {cc.Vec2} v1 
     * @param {cc.Vec2} v2 
     * @returns {number} radian 弧度
     */
    public static getRadian = (v1: cc.Vec2, v2: cc.Vec2): number => Math.atan2(v2.y - v1.y, v2.x - v1.x);

    /**
     * 获得随机方向
     * @returns {cc.Vec2} 返回一个带方向的随机向量
     */
    public static getRandomDirection = (): cc.Vec2 => cc.v2(Math.random() - 0.5, Math.random() - 0.5).normalize();

    /**
     * 反射单位向量
     * @param vn 入射单位向量
     * @param vi 反射单位向量
     * @returns 
     */
    public static getReflect(vn: cc.Vec2, vi: cc.Vec2) {
        vn = vn.normalize();
        // 入射单位向量
        vi = vi.normalize();
        // 反射单位向量 vr
        return vi.sub(vn.mul(2 * vi.dot(vn)));
    }

    /**
     * 获取两点间距离
     * @param p1X
     * @param p1Y
     * @param p2X
     * @param p2Y
     * @returns {number} 距离
     */
    public static getDistance(p1X: number, p1Y: number, p2X: number, p2Y: number): number {
        var disX: number = p2X - p1X;
        var disY: number = p2Y - p1Y;
        var disQ: number = disX * disX + disY * disY;
        return Math.sqrt(disQ);
    }

    //矩形与圆形检测
    static ComputeCollision(w, h, r, rx, ry) {
        var dx = Math.min(rx, w * 0.5);
        var dx1 = Math.max(dx, -w * 0.5);
        var dy = Math.min(ry, h * 0.5);
        var dy1 = Math.max(dy, -h * 0.5);
        return (dx1 - rx) * (dx1 - rx) + (dy1 - ry) * (dy1 - ry) <= r * r;
    }

    static circleRect(circle: cc.Node, rect: cc.Rect) {
        //圆的半径  
        var radius = circle.width / 2;
        //圆形中心与矩形中心的相对坐标  
        var x = circle.x - rect.x;
        var y = circle.y - rect.y;

        var minX = Math.min(x, rect.width * 0.5);
        var maxX = Math.max(minX, -rect.width * 0.5);
        var minY = Math.min(y, rect.height * 0.5);
        var maxY = Math.max(minY, -rect.height * 0.5);
        return (maxX - x) * (maxX - x) + (maxY - y) * (maxY - y) <= radius * radius;
    }

    /**
     * 将值x钳位到范围[a, b]
     * @param a 
     * @param b 
     * @param x 
     * @returns {number} a >= x <= b
     */
    public static clamp(a: number, b: number, x: number): number {
        if (a > b) {
            let t = a;
            a = b;
            b = t;
        }
        if (x < a) return a;
        if (x > b) return b;
        return x;
    }


    public static toFixedStr(value: number, fixCount: number): string {
        return value.toFixed(fixCount).replace(/\.?0*$/, '');
    }

    public static toPercentStr(value: number, fixCount: number): string {
        return this.toFixedStr(value * 100, fixCount) + "%";
    }

    public static toFixedWan(value: number): string {
        const wanFix = 100000;
        let wanFloat = wanFix / 10;
        var v = Math.floor(value / wanFloat) * wanFloat;
        return value > wanFix ? `${MathUtils.toFixedStr(v / wanFix * 10, 1)}万` : value.toString();
    }

    //value = ceil(e*(a*(level^d) + b*(level) + c))
    public static getFinalValueBasedOnParams(level: number, paramList: Array<number>, needCeil?: boolean): number {
        if (paramList.length < 5) {
            return 0;
        }
        let ret = paramList[4] * (paramList[0] * Math.pow(level, paramList[3]) + paramList[1] * level + paramList[2]);
        if (needCeil) {
            ret = Math.ceil(ret);
        }
        return ret;
    }

} 
